跳到主要内容

LCR 087.复原 IP 地址

· 阅读需 5 分钟

1、题干

给定一个只包含数字的字符串 s ,用以表示一个 IP 地址,返回所有可能从 s 获得的 有效 IP 地址 。你可以按任何顺序返回答案。

有效 IP 地址 正好由四个整数(每个整数位于 0 到 255 之间组成,且不能含有前导 0),整数之间用 '.' 分隔。

例如:"0.1.2.201" 和 "192.168.1.1" 是 有效 IP 地址,但是 "0.011.255.245"、"192.168.1.312" 和 "192.168@1.1" 是 无效 IP 地址。

 

示例 1:

输入:s = "25525511135"
输出:["255.255.11.135","255.255.111.35"]

示例 2:

输入:s = "0000"
输出:["0.0.0.0"]

示例 3:

输入:s = "1111"
输出:["1.1.1.1"]

示例 4:

输入:s = "010010"
输出:["0.10.0.10","0.100.1.0"]

示例 5:

输入:s = "10203040"
输出:["10.20.30.40","102.0.30.40","10.203.0.40"]

 

提示:

  • 0 <= s.length <= 3000
  • s 仅由数字组成

 

注意:本题与主站 93 题相同:https://leetcode-cn.com/problems/restore-ip-addresses/ 

2、解法1-嵌套循环

三层嵌套循环确定 IP 地址的4个子串,并检验其合法性


3、代码

var restoreIpAddresses = function (s) {
const n = s.length;
const valid = (str) => !((str.length > 1 && str[0] === '0') || +str > 255);

const res = [];
for (let i = 1; i < 4; i++) {
if (n - i < 3 || n - i > 9) continue;
for (let j = i + 1; j < i + 4; j++) {
if (n - j < 2 || n - j > 6) continue;
for (let k = j + 1; k < j + 4; k++) {
if (n - k < 1 || n - k > 3) continue;
const s1 = s.slice(0, i), s2 = s.slice(i, j);
const s3 = s.slice(j, k), s4 = s.slice(k);
if (valid(s1) && valid(s2) && valid(s3) && valid(s4)) res.push(`${s1}.${s2}.${s3}.${s4}`);
}
}
}

return res;
};

代码中的校验可以简化,但遍历次数会增加

var restoreIpAddresses = function (s) {
const valid = (str) => !(str.length < 1 || str.length > 3 || (str.length > 1 && str[0] === '0') || +str > 255);

const res = [];
for (let i = 1; i < 4; i++) {
for (let j = i + 1; j < i + 4; j++) {
for (let k = j + 1; k < j + 4; k++) {
const s1 = s.slice(0, i), s2 = s.slice(i, j);
const s3 = s.slice(j, k), s4 = s.slice(k);
if (valid(s1) && valid(s2) && valid(s3) && valid(s4)) res.push(`${s1}.${s2}.${s3}.${s4}`);
}
}
}

return res;
};

4、执行结果

image.png


5、解法2-回溯

使用回溯算法,在字符串 s 中选取3个索引作为选择路径(idxArr),其中索引值用于将字符串 s 分割成4个 IP 子串,以子串长度作为选择列表。

注意

  • 选择列表(子串长度)只有 123 三种选择
  • 为了代码简洁性,每次递归都传入不同引用的选择路径(idxArr),这样可以省略撤销操作,但是消耗的内存会偏多

6、代码

var restoreIpAddresses = function (s) {
const n = s.length;
const valid = (str) => !((str.length > 1 && str[0] === '0') || +str > 255);

const res = [];
function backtrace(idxArr) {
const ln = idxArr.length, li = idxArr[ln - 1] || 0;

if (n - li < 4 - ln || n - li > 3 * (4 - ln)) return;
if (ln === 3) {
const s1 = s.slice(0, idxArr[0]), s2 = s.slice(idxArr[0], idxArr[1]);
const s3 = s.slice(idxArr[1], idxArr[2]), s4 = s.slice(idxArr[2]);
if (valid(s1) && valid(s2) && valid(s3) && valid(s4)) res.push(`${s1}.${s2}.${s3}.${s4}`);
return;
}

for (let i = 1; i <= 3; i++) backtrace([...idxArr, li + i]);
}

return backtrace([]), res;
};

7、执行结果

  • 执行用时: 68 ms
  • 内存消耗: 43.4 MB